﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Unicode;

namespace XF.FM.Core.Options
{
    public class XfJsonOption : IXfOption
    {

        private string _file;
        private object _value;
        private Type _valueType;
        private XfOptionConfig _optionConfig;
        private bool _success = false;
        private bool _createFile = false;
        //public static XfOptionConfig defaultXfOptionConfig = new XfOptionConfig() { FileDir = "xfconfig", FileEncoding = Encoding.GetEncoding("GBK") };
        //public static JsonSerializerOptions defaultJsonSerializerOptions = new JsonSerializerOptions()
        //{
        //    WriteIndented = true,
        //    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All)
        //};
        public XfJsonOption(Type valueType, string file) : this(valueType, file, XfConfig.DefaultXfOptionConfig)
        {

        }
        public XfJsonOption(Type valueType, string file, XfOptionConfig optionConfig)
        {
            if (valueType == null)
                throw new ArgumentNullException(nameof(valueType));
            if (file == null)
                throw new ArgumentNullException(nameof(file));
            this._valueType = valueType;
            if (file.EndsWith(".json"))
                this._file = file.Substring(0, file.Length - 5);
            else
                this._file = file;
            _optionConfig = optionConfig;
        }
        public XfJsonOption(object obj, string file, XfOptionConfig xfOptionConfig = null)
        {
            if (obj == null)
                throw new ArgumentNullException(nameof(obj));
            if (xfOptionConfig == null)
            {
                _optionConfig =XfConfig.DefaultXfOptionConfig;
            }
            this._valueType = obj.GetType();
            this._value = obj;
            this._file = file;
            _createFile = true;
        }
        public string Key => _file;

        public object Value => _value;
        public T GetValue<T>() where T : class
        {
            if (_value is T)
            {
                return (T)_value;
            }
            else
            {
                throw new Exception($"{typeof(T).Name}类型不正确");
            }
        }

        public Type ValueType => _valueType;
        public bool IsSuccess => _success;
        public void Init()
        {
            if (_createFile)
                InitObj();
            else
                InitFile();
        }
        private void InitFile()
        {
            var valiResult = this.Validate(true);
            if (valiResult.Item1 == true)
            {
                _success = true;
                _value = valiResult.Item2;
            }
        }
        private void InitObj()
        {
            string filePath = Path.Combine(_optionConfig.FileDir, JsonFileName);
            if (!Directory.Exists(_optionConfig.FileDir))
            {
                Directory.CreateDirectory(_optionConfig.FileDir);
            }
            if (File.Exists(filePath))
                return;
            else
            {
                string jsonString = JsonSerializer.Serialize(this._value, this._valueType,XfConfig.DefaultJsonSerializerOptions);
                File.WriteAllText(filePath, jsonString, _optionConfig.FileEncoding);
            }
        }
        public string Reload()
        {
            var valiResult = this.Validate(false);
            if (valiResult.Item1 == true)
            {
                _value = valiResult.Item2;
                return "";
            }
            else
            {
                return (string)valiResult.Item2;
            }
        }
        public void ReSet(object optionValue)
        {
            if (optionValue == null)
                throw new ArgumentNullException(nameof(optionValue));
            if (optionValue.GetType() != _valueType)
                throw new Exception($"传入的类型不正确,需要{_valueType.FullName},传入的{optionValue.GetType()}");
            _value = optionValue;
            var jsonString = JsonSerializer.Serialize(optionValue, _valueType,XfConfig.DefaultJsonSerializerOptions);
            string filePath = Path.Combine(_optionConfig.FileDir, JsonFileName);
            File.WriteAllText(filePath, jsonString, _optionConfig.FileEncoding);
        }
        public Tuple<bool?, object> Validate()
        {
            return Validate(false);
        }
        private Tuple<bool?, object> Validate(bool throwExp)
        {
            string filePath = Path.Combine(_optionConfig.FileDir, JsonFileName);
            if (!File.Exists(filePath))
            {
                if (throwExp)
                    throw new FileNotFoundException("找不到配置文件", filePath);
                else
                    return Tuple.Create<bool?, object>(null, "找不到配置文件:" + filePath);
            }
            try
            {
                var obj = JsonSerializer.Deserialize(File.ReadAllText(filePath, _optionConfig.FileEncoding), this.ValueType, XfConfig.DefaultJsonSerializerOptions);
                return Tuple.Create<bool?, object>(true, obj);
            }
            catch (JsonException exp)
            {
                if (throwExp)
                    throw new JsonException("Json文件格式不正确或指定类型不正确", exp.Path, exp.LineNumber, exp.BytePositionInLine);
                else
                    return Tuple.Create<bool?, object>(false, $"Json文件格式不正确或指定类型不正确,path:{exp.Path},type:{_valueType.FullName},LineNumber:{exp.LineNumber}");
            }
            catch (Exception exp)
            {
                throw exp;
            }
        }
        public string JsonFileName => _file + ".json";
    }
}
